Last substring in lexicographical order¶
Time: O(N); Space: O(N); hard
Given a string s, return the last substring of s in lexicographical order.
Example 1:
Input: s = “abab”
Output: “bab”
Explanation:
The substrings are [“a”, “ab”, “aba”, “abab”, “b”, “ba”, “bab”].
The lexicographically maximum substring is “bab”.
Example 2:
Input: s = “leetcode”
Output: “tcode”
Notes:
1 <= len(s) <= 4 * 10^5
s contains only lowercase English letters.
Hints:
Assume that the answer is a sub-string from index i to j. If you add the character at index j+1 you get a better answer.
The answer is always a suffix of the given string.
Since the limits are high, we need an efficient data structure.
Use suffix array.
[3]:
import collections
class Solution1(object):
"""
Time: O(n)
Space: O(n)
"""
def lastSubstring(self, s):
"""
:type s: str
:rtype: str
"""
count = collections.defaultdict(list)
for i in range(len(s)):
count[s[i]].append(i)
max_c = max(count.keys())
starts = {}
for i in count[max_c]:
starts[i] = i+1
while len(starts)-1 > 0:
lookup = set()
next_count = collections.defaultdict(list)
for start, end in starts.items():
if end == len(s): # finished
lookup.add(start)
continue
next_count[s[end]].append(start)
if end in starts: # overlapped
lookup.add(end)
next_starts = {}
max_c = max(next_count.keys())
for start in next_count[max_c]:
if start not in lookup:
next_starts[start] = starts[start] + 1
starts = next_starts
return s[list(map(int, starts.keys()))[0]:]
[4]:
sol = Solution1()
s = "abab"
assert sol.lastSubstring(s) == "bab"
s = "leetcode"
assert sol.lastSubstring(s) == "tcode"
[5]:
class Solution2(object):
def lastSubstring(self, s):
"""
:type s: str
:rtype: str
"""
chars = set(s)
if len(chars) == 1:
return s
start = sorted(chars, reverse=True)[0]
possibles = []
for i, c in enumerate(s):
if c == start:
possibles.append([i, i])
while len(possibles) > 1:
cs = []
tmp = []
for i, j in possibles:
if j + 1 >= len(s):
continue
cs.append(s[j + 1])
m = max(cs)
for i, j in possibles:
if j + 1 >= len(s):
continue
if s[j + 1] == m:
tmp.append([i, j + 1])
possibles = tmp
return s[possibles[0][0]:]
[6]:
sol = Solution2()
s = "abab"
assert sol.lastSubstring(s) == "bab"
s = "leetcode"
assert sol.lastSubstring(s) == "tcode"